New memory_op subcall XENMEM_translate_gpfn_list.
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 16 Feb 2006 17:52:06 +0000 (18:52 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 16 Feb 2006 17:52:06 +0000 (18:52 +0100)
Allows translation from GPFNs to MFNs for an auto-translated
guest.

Signed-off-by: Keir Fraser <keir@xensource.com>
tools/libxc/xc_domain.c
tools/libxc/xc_private.c
tools/libxc/xenctrl.h
xen/common/memory.c
xen/include/public/memory.h

index 89bdb86e5dcf58baf948094a3d7f0a7682afb0cc..ea2ca76d1b0371b827177d2ecde2742e8d1402c3 100644 (file)
@@ -326,6 +326,53 @@ int xc_domain_memory_decrease_reservation(int xc_handle,
     return err;
 }
 
+int xc_domain_memory_populate_physmap(int xc_handle,
+                                          uint32_t domid,
+                                          unsigned long nr_extents,
+                                          unsigned int extent_order,
+                                          unsigned int address_bits,
+                                          unsigned long *extent_start)
+{
+    int err;
+    struct xen_memory_reservation reservation = {
+        .extent_start = extent_start,
+        .nr_extents   = nr_extents,
+        .extent_order = extent_order,
+        .address_bits = address_bits,
+        .domid        = domid
+    };
+
+    err = xc_memory_op(xc_handle, XENMEM_populate_physmap, &reservation);
+    if ( err == nr_extents )
+        return 0;
+
+    if ( err > 0 )
+    {
+        fprintf(stderr,"Failed deallocation for dom %d: %ld pages order %d\n",
+                domid, nr_extents, extent_order);
+        errno = EBUSY;
+        err = -1;
+    }
+
+    return err;
+}
+
+int xc_domain_translate_gpfn_list(int xc_handle,
+                                  uint32_t domid,
+                                  unsigned long nr_gpfns,
+                                  unsigned long *gpfn_list,
+                                  unsigned long *mfn_list)
+{
+    struct xen_translate_gpfn_list op = {
+        .domid        = domid,
+        .nr_gpfns     = nr_gpfns,
+        .gpfn_list    = gpfn_list,
+        .mfn_list     = mfn_list
+    };
+
+    return xc_memory_op(xc_handle, XENMEM_translate_gpfn_list, &op);
+}
+
 int xc_domain_max_vcpus(int xc_handle, uint32_t domid, unsigned int max)
 {
     DECLARE_DOM0_OP;
index 70d5d6829af873b9effc60a55853926ba06c9aca..edf55d360ca2d39019fb0ac316e453da2a573d11 100644 (file)
@@ -191,6 +191,7 @@ int xc_memory_op(int xc_handle,
     DECLARE_HYPERCALL;
     struct xen_memory_reservation *reservation = arg;
     struct xen_machphys_mfn_list *xmml = arg;
+    struct xen_translate_gpfn_list *trans = arg;
     long ret = -EINVAL;
 
     hypercall.op     = __HYPERVISOR_memory_op;
@@ -237,6 +238,26 @@ int xc_memory_op(int xc_handle,
             goto out1;
         }
         break;
+    case XENMEM_translate_gpfn_list:
+        if ( mlock(trans, sizeof(*trans)) != 0 )
+        {
+            PERROR("Could not mlock");
+            goto out1;
+        }
+        if ( mlock(trans->gpfn_list, trans->nr_gpfns * sizeof(long)) != 0 )
+        {
+            PERROR("Could not mlock");
+            safe_munlock(trans, sizeof(*trans));
+            goto out1;
+        }
+        if ( mlock(trans->mfn_list, trans->nr_gpfns * sizeof(long)) != 0 )
+        {
+            PERROR("Could not mlock");
+            safe_munlock(trans->gpfn_list, trans->nr_gpfns * sizeof(long));
+            safe_munlock(trans, sizeof(*trans));
+            goto out1;
+        }
+        break;
     }
 
     ret = do_xen_hypercall(xc_handle, &hypercall);
@@ -259,6 +280,11 @@ int xc_memory_op(int xc_handle,
     case XENMEM_reserved_phys_area:
         safe_munlock(arg, sizeof(struct xen_reserved_phys_area));
         break;
+    case XENMEM_translate_gpfn_list:
+            safe_munlock(trans->mfn_list, trans->nr_gpfns * sizeof(long));
+            safe_munlock(trans->gpfn_list, trans->nr_gpfns * sizeof(long));
+            safe_munlock(trans, sizeof(*trans));
+        break;
     }
 
  out1:
index dc6a9c0f83dd68edfff6059375c239f3ea2b808f..282a6f9e67427c0164c278495b16a698ef4973d0 100644 (file)
@@ -373,6 +373,19 @@ int xc_domain_memory_decrease_reservation(int xc_handle,
                                           unsigned int extent_order,
                                          unsigned long *extent_start);
 
+int xc_domain_memory_populate_physmap(int xc_handle,
+                                      uint32_t domid,
+                                      unsigned long nr_extents,
+                                      unsigned int extent_order,
+                                      unsigned int address_bits,
+                                      unsigned long *extent_start);
+
+int xc_domain_translate_gpfn_list(int xc_handle,
+                                  uint32_t domid,
+                                  unsigned long nr_gpfns,
+                                  unsigned long *gpfn_list,
+                                  unsigned long *mfn_list);
+
 int xc_domain_ioport_permission(int xc_handle,
                                 uint32_t domid,
                                 uint32_t first_port,
index 320e8c3d6ec05fc3b9d13c93c5c7d1977cebbb22..40a2d9c14d43e127ad510bffa9c6a51a57abe304 100644 (file)
 #include <asm/hardirq.h>
 #include <public/memory.h>
 
+/*
+ * To allow safe resume of do_memory_op() after preemption, we need to know 
+ * at what point in the page list to resume. For this purpose I steal the 
+ * high-order bits of the @cmd parameter, which are otherwise unused and zero.
+ */
+#define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */
+
 static long
 increase_reservation(
     struct domain *d, 
@@ -188,17 +195,74 @@ decrease_reservation(
     return nr_extents;
 }
 
-/*
- * To allow safe resume of do_memory_op() after preemption, we need to know 
- * at what point in the page list to resume. For this purpose I steal the 
- * high-order bits of the @cmd parameter, which are otherwise unused and zero.
- */
-#define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */
+static long
+translate_gpfn_list(
+    struct xen_translate_gpfn_list *uop, unsigned long *progress)
+{
+    struct xen_translate_gpfn_list op;
+    unsigned long i, gpfn, mfn;
+    struct domain *d;
+
+    if ( copy_from_user(&op, uop, sizeof(op)) )
+        return -EFAULT;
+
+    /* Is size too large for us to encode a continuation? */
+    if ( op.nr_gpfns > (ULONG_MAX >> START_EXTENT_SHIFT) )
+        return -EINVAL;
+
+    if ( !array_access_ok(op.gpfn_list, op.nr_gpfns, sizeof(*op.gpfn_list)) ||
+         !array_access_ok(op.mfn_list, op.nr_gpfns, sizeof(*op.mfn_list)) )
+        return -EFAULT;
 
-long do_memory_op(int cmd, void *arg)
+    if ( op.domid == DOMID_SELF )
+        op.domid = current->domain->domain_id;
+    else if ( !IS_PRIV(current->domain) )
+        return -EPERM;
+
+    if ( (d = find_domain_by_id(op.domid)) == NULL )
+        return -ESRCH;
+
+    if ( !shadow_mode_translate(d) )
+    {
+        put_domain(d);
+        return -EINVAL;
+    }
+
+    for ( i = *progress; i < op.nr_gpfns; i++ )
+    {
+        if ( hypercall_preempt_check() )
+        {
+            put_domain(d);
+            *progress = i;
+            return -EAGAIN;
+        }
+
+        if ( unlikely(__copy_from_user(&gpfn, &op.gpfn_list[i],
+                                       sizeof(gpfn))) )
+        {
+            put_domain(d);
+            return -EFAULT;
+        }
+
+        mfn = gmfn_to_mfn(d, gpfn);
+
+        if ( unlikely(__copy_to_user(&op.mfn_list[i], &mfn,
+                                     sizeof(mfn))) )
+        {
+            put_domain(d);
+            return -EFAULT;
+        }
+    }
+
+    put_domain(d);
+    return 0;
+}
+
+long do_memory_op(unsigned long cmd, void *arg)
 {
     struct domain *d;
-    int rc, start_extent, op, flags = 0, preempted = 0;
+    int rc, op, flags = 0, preempted = 0;
+    unsigned long start_extent, progress;
     struct xen_memory_reservation reservation;
     domid_t domid;
 
@@ -212,6 +276,10 @@ long do_memory_op(int cmd, void *arg)
         if ( copy_from_user(&reservation, arg, sizeof(reservation)) )
             return -EFAULT;
 
+        /* Is size too large for us to encode a continuation? */
+        if ( reservation.nr_extents > (ULONG_MAX >> START_EXTENT_SHIFT) )
+            return -EINVAL;
+
         start_extent = cmd >> START_EXTENT_SHIFT;
         if ( unlikely(start_extent > reservation.nr_extents) )
             return -EINVAL;
@@ -302,6 +370,16 @@ long do_memory_op(int cmd, void *arg)
 
         break;
 
+    case XENMEM_translate_gpfn_list:
+        progress = cmd >> START_EXTENT_SHIFT;
+        rc = translate_gpfn_list(arg, &progress);
+        if ( rc == -EAGAIN )
+            return hypercall2_create_continuation(
+                __HYPERVISOR_memory_op,
+                op | (progress << START_EXTENT_SHIFT),
+                arg);
+        break;
+
     default:
         rc = arch_memory_op(op, arg);
         break;
index 3f24bb538611a128d01af030e8cdce0632fd5c71..eb99be99ef4c92c227fe97c9918ff778933f9ae1 100644 (file)
@@ -101,7 +101,7 @@ typedef struct xen_machphys_mfn_list {
  */
 #define XENMEM_reserved_phys_area   7
 typedef struct xen_reserved_phys_area {
-    /* Which request to report about? */
+    /* Which domain to report about? */
     domid_t domid;
 
     /*
@@ -114,6 +114,28 @@ typedef struct xen_reserved_phys_area {
     unsigned long first_gpfn, nr_gpfns;
 } xen_reserved_phys_area_t;
 
+/*
+ * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error
+ * code on failure. This call only works for auto-translated guests.
+ */
+#define XENMEM_translate_gpfn_list  8
+typedef struct xen_translate_gpfn_list {
+    /* Which domain to translate for? */
+    domid_t domid;
+
+    /* Length of list. */
+    unsigned long nr_gpfns;
+
+    /* List of GPFNs to translate. */
+    unsigned long *gpfn_list;
+
+    /*
+     * Output list to contain MFN translations. May be the same as the input
+     * list (in which case each input GPFN is overwritten with the output MFN).
+     */
+    unsigned long *mfn_list;
+} xen_translate_gpfn_list_t;
+
 #endif /* __XEN_PUBLIC_MEMORY_H__ */
 
 /*